/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package br.com.saber.certificacao.beansjsf.prova;

import br.com.saber.certificacao.beansjsf.interfacebean.BeanJSFInterface;
import br.com.saber.certificacao.beansjsf.login.LoginManager;
import br.com.saber.certificacao.beansjsf.prova.controler.ProvaService;
import br.com.saber.certificacao.beansjsf.prova.controler.implementacao.ProvaComentada;
import br.com.saber.certificacao.beansjsf.prova.controler.implementacao.ProvaDireta;
import br.com.saber.certificacao.beansjsf.prova.controler.implementacao.ProvaNoBack;
import br.com.saber.certificacao.beansjsf.semescopo.SelectItemManager;
import br.com.saber.certificacao.ejbs.stateless.interfaces.ProvaBeanLocal;
import br.com.saber.certificacao.enums.TipoProva;
import br.com.saber.certificacao.modelos.Prova;
import br.com.saber.certificacao.modelos.Resposta;
import br.com.saber.certificacao.modelos.relacionamentos.ProvaQuestao;
import br.com.saber.certificacao.observador.ControleObserver;
import br.com.saber.certificacao.utils.UtilMetodos;
import java.util.List;
import java.util.Observable;
import java.util.Observer;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.ejb.EJB;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ManagedProperty;
import javax.faces.bean.ViewScoped;
import javax.faces.context.FacesContext;
import javax.faces.event.ActionEvent;
import javax.faces.model.SelectItem;
import org.apache.commons.lang.StringUtils;
import org.primefaces.model.chart.PieChartModel;

/**
 *  Ainda não sei como farei a prova comentada e a prova direta, implementarei primeiro a prova direta
 * depois irei analisar a prova comentada...
 * @author gbvbahia
 */
@ManagedBean(name = "provaResponderManager")
@ViewScoped
public class ProvaResponderManager implements BeanJSFInterface, Observer {

    @EJB
    private ProvaBeanLocal provaBean;
    //Servico de controle de exebição de prova.
    private boolean title = true;
    private ProvaService provaService;
    private List<Prova> historicoProvas;
    private PieChartModel pieModel;
    @ManagedProperty("#{loginManager}")
    private LoginManager loginManager;
    @ManagedProperty("#{selectItemManager}")
    private SelectItemManager selectItemManager;
    @ManagedProperty("#{fluxoExibicaoProva}")
    private FluxoExibicao fluxoExibicaoProva;

    /** Creates a new instance of ProvaResponderManager */
    public ProvaResponderManager() {
    }

    //====================
    // Iniciadores
    //====================
    @Override
    @PostConstruct
    public void init() {
        ControleObserver.addBeanObserver(loginManager.getUsuario(), this);
        verificaProvaPendente();
        Logger.getLogger(this.getClass().getName()).log(Level.FINEST, "ProvaResponderManager.init() executado!");
    }

    @Override
    @PreDestroy
    public void end() {
        ControleObserver.removeBeanObserver(this.loginManager.getUsuario(), this);
        Logger.getLogger(this.getClass().getName()).log(Level.FINEST, "ProvaResponderManager.end() executado!");
    }

    //====================
    //Métodos de Negócio
    //====================
    @Override
    public void update(Observable o, Object arg) {
        String[] args = (String[]) arg;
        for (int i = 0; i < args.length; i++) {
            if (args[i].equals(ControleObserver.Eventos.PROVA_TERMINO) || args[i].equals(ControleObserver.Eventos.PROVA_CRIACAO)) {
                verificaProvaPendente();
                contabilizarAcertosErros();
            }
        }
    }

    /**-------------------------------------
     * Relativo ao botão avaliar
     * Verifica se questão está correta e se estiver
     * libera visualização das observações.
     * @param event 
     */
    public void liberarObservacao(ActionEvent event) {
        if (provaService != null) {
            this.provaService.liberarObservacao(FacesContext.getCurrentInstance());
        }
    }

    /**
     * Libera visualização da proxima questão
     * @param event 
     */
    public void questaoProxima(ActionEvent event) {
        if (provaService != null) {
            this.provaService.questaoProxima();
            contabilizarAcertosErros();
        }
    }

    /**
     * Libera visualização da questão anterior
     * @param event 
     */
    public void questaoAnterior(ActionEvent event) {
        if (provaService != null) {
            this.provaService.questaoAnterior();
            contabilizarAcertosErros();
        }
    }

    /**
     * Termina a prova e salva no banco de dados.
     */
    public void terminarProva() {
        if (provaService != null) {
            this.provaService.terminarProva(FacesContext.getCurrentInstance(), loginManager);
        }
        fluxoExibicaoProva.metodoExibirProvaHistorico();
    }

    /**
     * Salva a prova no banco de dados
     */
    public void atualizaProva() {
        if (provaService != null) {
            this.provaService.atualizaProva();
            contabilizarAcertosErros();
        }
    }

    /**
     * Contabiliza acertos e erros para ser exibido no pieChart
     */
    private void contabilizarAcertosErros() {
        pieModel = new PieChartModel();
        if (exibirPieChart()) {
            double acertos = 0;
            double erros = 0;
            for (ProvaQuestao pq : this.provaService.getProvaQuestoes()) {
                if (pq.isRespondida()) {
                    if (this.provaBean.isRespostaCorreta(pq)) {
                        acertos++;
                    } else {
                        erros++;
                    }
                }
            }
            String ok = UtilMetodos.getResourceBundle("acertos", FacesContext.getCurrentInstance()) + " " + UtilMetodos.getDuasCasasDecimais(acertos, erros);
            String nok = UtilMetodos.getResourceBundle("erros", FacesContext.getCurrentInstance()) + " " + UtilMetodos.getDuasCasasDecimais(erros, acertos);
            pieModel.set(ok, acertos);
            pieModel.set(nok, erros);
        }
    }

    /**
     * Verifica se existe alguma prova pendete a ser terminada de responder.
     */
    private void verificaProvaPendente() {
        List<Prova> provas = provaBean.buscarProvaPorStatus(this.loginManager.getUsuario(), false);
        if (!provas.isEmpty()) {
            //Somente uma prova pode estar pendente, se houver mais pega a 1ª
            Prova prova = provas.get(0);
            setProva(prova);
        } else {
            this.provaService = null;
        }
        this.historicoProvas = this.provaBean.buscarProvaPorStatus(loginManager.getUsuario(), true);
    }

    public void setProva(Prova prova) {
        if (prova.getTipoProva().equals(TipoProva.COMENTADA)) {
            this.provaService = new ProvaComentada(prova, this.provaBean);
        } else if (prova.getTipoProva().equals(TipoProva.DIRETA)) {
            this.provaService = new ProvaDireta(prova, this.provaBean);
        } else if (prova.getTipoProva().equals(TipoProva.NO_BACK)) {
            this.provaService = new ProvaNoBack(prova, this.provaBean);
        }
        this.provaService.exibeInformacaoSobreTipoDeProva(FacesContext.getCurrentInstance());
        fluxoExibicaoProva.metodoExibirProvaResponde();
    }

    //====================
    //Table Actions
    //====================
    //====================
    //SelectItem
    //====================
    public List<SelectItem> getRespostasDisponiveis() {
        if (provaService != null) {
            return this.provaService.getRespostasDisponiveis(selectItemManager);
        }
        return null;
    }

    //=========================
    //Getters AND Setters
    //=========================
    public LoginManager getLoginManager() {
        return loginManager;
    }

    public void setLoginManager(LoginManager loginManager) {
        this.loginManager = loginManager;
    }

    public SelectItemManager getSelectItemManager() {
        return selectItemManager;
    }

    public void setSelectItemManager(SelectItemManager selectItemManager) {
        this.selectItemManager = selectItemManager;
    }

    public ProvaQuestao getQuestaoAtual() {
        if (provaService != null) {
            return provaService.getQuestaoAtual();
        }
        return null;
    }

    public boolean isExisteQuestaoAnterior() {
        if (provaService != null) {
            return provaService.isExisteQuestaoAnterior();
        }
        return false;
    }

    public boolean isExisteQuestaoProxima() {
        if (provaService != null) {
            return provaService.isExisteQuestaoProxima();
        }
        return false;
    }

    public boolean isUnicaEscolha() {
        if (provaService != null) {
            return provaService.isUnicaEscolha();
        }
        return false;
    }

    public boolean isLiberaComentarios() {
        if (provaService != null) {
            return this.provaService.isLiberaObservacao(FacesContext.getCurrentInstance());
        }
        return false;
    }

    public boolean exibirPieChart() {
        if (provaService != null) {
            return this.provaService.tipoProva(FacesContext.getCurrentInstance()).equals(TipoProva.NO_BACK);
        }
        return false;
    }

    public List<ProvaQuestao> getProvaQuestoesUm() {
        if (provaService != null) {
            return provaService.getProvaQuestoesUm();
        }
        return null;
    }

    public List<ProvaQuestao> getProvaQuestoesDois() {
        if (provaService != null) {
            return provaService.getProvaQuestoesDois();
        }
        return null;
    }

    public List<ProvaQuestao> getProvaQuestoesTres() {
        if (provaService != null) {
            return provaService.getProvaQuestoesTres();
        }
        return null;
    }

    public Resposta getRespostaMarcada() {
        if (provaService != null) {
            return this.provaService.getRespostaMarcada();
        }
        return null;
    }

    public void setRespostaMarcada(Resposta respostaMarcada) {
        if (provaService != null) {
            this.provaService.setRespostaMarcada(respostaMarcada);
        }
    }

    public List<Resposta> getRespostasMarcadas() {
        if (provaService != null) {
            return this.provaService.getRespostasMarcadas();
        }
        return null;
    }

    public void setRespostasMarcadas(List<Resposta> respostasMarcadas) {
        if (provaService != null) {
            this.provaService.setRespostasMarcadas(respostasMarcadas);
        }
    }

    public ProvaService getProvaService() {
        return provaService;
    }

    /**
     * Define se comentários de respostas e questões serão exibidos
     * @return true para prova comentada false para prova sem comentários
     */
    public boolean isProvaComentada() {
        if (provaService != null) {
            return this.provaService.isProvaComentada(FacesContext.getCurrentInstance());
        }
        return false;
    }

    /**
     * Retorna a lista das observações das respostas para serem exibidas na prova.
     * @return 
     */
    public List<String> getRespostasDisponiveisObservacao() {
        if (provaService != null) {
            return this.provaService.getRespostasDisponiveisObservacao(FacesContext.getCurrentInstance());
        }
        return null;
    }

    public List<Prova> getHistoricoProvas() {
        return historicoProvas;
    }

    public void setHistoricoProvas(List<Prova> historicoProvas) {
        this.historicoProvas = historicoProvas;
    }

    public FluxoExibicao getFluxoExibicaoProva() {
        return fluxoExibicaoProva;
    }

    public void setFluxoExibicaoProva(FluxoExibicao fluxoExibicaoProva) {
        this.fluxoExibicaoProva = fluxoExibicaoProva;
    }

    public int getLinhas() {
        int toReturn = StringUtils.countMatches(getQuestaoAtual().getQuestao().getEnunciado(), "\n");
        return toReturn > 6 ? 6 : toReturn < 3 ? 3 : toReturn;
    }

    public PieChartModel getPieModel() {
        if (this.pieModel == null) {
            contabilizarAcertosErros();
        }
        return pieModel;
    }

    public void setPieModel(PieChartModel pieModel) {
        this.pieModel = pieModel;
    }

    public boolean isTitle() {
        return title;
    }

    public void setTitle(boolean title) {
        this.title = title;
    }
    
    public String getTitleEnunciado(){
        if(title && this.provaService != null){
            return this.provaService.getQuestaoAtual().getQuestao().getEnunciado();
        }
        return null;
    }
}
